package com.beta.admin.support.auth;

import com.beta.entity.AdminRoles;
import com.beta.service.IAdminRolesService;
import com.beta.service.IAdminsService;
import com.beta.service.IMenusService;
import com.beta.entity.Admins;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.mindrot.jbcrypt.BCrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Created by vector on 2017/1/1.
 */
@Service
public class AdminAuthRealm extends AuthorizingRealm {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private IAdminsService adminsService;
    private IAdminRolesService adminRolesService;
    private IMenusService menusService;

    @Autowired
    private void setAdminsService(IAdminsService adminsService) {
        this.adminsService = adminsService;
    }

    @Autowired
    public AdminAuthRealm setAdminRolesService(IAdminRolesService adminRolesService) {
        this.adminRolesService = adminRolesService;
        return this;
    }

    @Autowired
    public AdminAuthRealm setMenusService(IMenusService menusService) {
        this.menusService = menusService;
        return this;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Admins admins = (Admins) principals.getPrimaryPrincipal();
        List<AdminRoles> adminRoles = adminRolesService.getAdminRolesById(admins.getId());
        Set<String> roleNameSet = adminRoles.stream().map(AdminRoles::getName).collect(Collectors.toSet());

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roleNameSet);
        Map<String, String> adminMenuActionsMap = menusService.getAdminMenuActionsMap(admins.getId());
        adminMenuActionsMap.forEach((menu, actions) -> {
            String wildcardString = buildWildcardPermissionString(menu, actions);
            if (StringUtils.isNotBlank(wildcardString)) {
                simpleAuthorizationInfo.addObjectPermission(new WildcardPermission(wildcardString));
            }
        });
        return simpleAuthorizationInfo;
    }

    private String buildWildcardPermissionString(String menu, String actions) {
        if (StringUtils.isAnyBlank(menu, actions)) {
            return "";
        }
        return String.join(":", menu, actions);
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        logger.info("用户登录：userInfo={}", usernamePasswordToken);

        Admins admins = adminsService.findAdminByName(usernamePasswordToken.getUsername());
        if (Objects.isNull(admins)) {
            throw new UnknownAccountException();
        }

        boolean validPassword = BCrypt.checkpw(String.valueOf(usernamePasswordToken.getPassword()), admins.getEncryptedPassword());
        if (!validPassword) {
            throw new IncorrectCredentialsException();
        }

        return new SimpleAuthenticationInfo(admins, usernamePasswordToken.getPassword(), getClass().getName());
    }

}
